/**
 * @file test_LUT.cpp
 * @author 逆流 (1171267147@qq.com)
 * @brief 测试LUT函数，将单通道图按特定规则映射为多通道
 * @version 0.1
 * @date 2024-07-03
 *
 * @copyright Copyright (c) 2024
 *
 */

#include <iostream>
#include <opencv2/opencv.hpp>
#include <string>
#include <vector>

#include "my_tools.h"

using namespace cv;
using namespace std;

const Vec3b kBlue(255, 0, 0);
const Vec3b kGreen(0, 255, 0);
const Vec3b kRed(0, 0, 255);
static int  Distance(Point2i start, Point2i end) { return sqrt(pow(start.x - end.x, 2) + pow(start.y - end.y, 2)); }

void CreateSrcImage(Mat &src) {
    src = Mat::zeros(Size(256, 256), CV_8UC1);

    const Point2i kCenter(src.cols / 2, src.rows / 2);

    auto SetPixel = [&src, &kCenter](int radius, int width, int value) {
        for (int row = 0; row < src.rows; row++) {
            for (int col = 0; col < src.cols; col++) {
                auto distance = Distance(Point2i(row, col), kCenter);
                if (distance > radius && distance < radius + width) {
                    src.at<uchar>(row, col) = value;
                }
            }
        }
    };

    SetPixel(20, 5, 1);
    SetPixel(50, 5, 2);
    SetPixel(80, 5, 3);
}

void CreateBGRTable(Mat &table) {
    Mat blue_table  = Mat::zeros(1, 256, CV_8UC1);
    Mat green_table = Mat::zeros(1, 256, CV_8UC1);
    Mat red_table   = Mat::zeros(1, 256, CV_8UC1);

    auto *blue_ptr  = blue_table.ptr();
    auto *green_ptr = green_table.ptr();
    auto *red_ptr   = red_table.ptr();

    for (int i = 1; i <= 3; i++) {
        Vec3b color;
        if (i == 1) {
            color = kBlue;
        } else if (i == 2) {
            color = kGreen;
        } else {
            color = kRed;
        }

        blue_ptr[i]  = color[0];
        green_ptr[i] = color[1];
        red_ptr[i]   = color[2];
    }

    vector<Mat> channels;
    channels.push_back(blue_table);
    channels.push_back(green_table);
    channels.push_back(red_table);
    cv::merge(channels, table);
}

int main(void) {
    cpp_sdk_test::Timer timer;

    Mat src;
    Mat dest;

    CreateSrcImage(src);

    const string kTitle = "show";

    Mat   gray_table = Mat::zeros(256, 1, CV_8UC1);
    auto *ptr        = gray_table.ptr();

    ptr[1] = 63;
    ptr[2] = 128;
    ptr[3] = 255;

    timer.Start();
    LUT(src, gray_table, dest);
    timer.End();

    cout << "Gray LUT spend time: " << timer.AverageTime() << "us" << '\n';
    imshow(kTitle, dest);
    waitKey(0);

    Mat rgb_table;
    CreateBGRTable(rgb_table);

    timer.Start();
    Mat         rgb_src;
    vector<Mat> src_channels{src, src, src};
    cv::merge(src_channels, rgb_src);

    LUT(rgb_src, rgb_table, dest);
    timer.End();

    cout << "LUT spend time: " << timer.AverageTime() << " us" << '\n';
    imshow(kTitle, dest);
    waitKey(0);

    timer.Start();
    dest     = Mat::zeros(src.size(), CV_8UC3);
    int rows = src.rows;
    int cols = src.cols * src.channels();
    if (src.isContinuous() && dest.isContinuous()) {
        cols *= rows;
        rows = 1;
    }

    for (int i = 0; i < rows; ++i) {
        auto *data      = src.ptr(i, 0);
        auto *dest_data = dest.ptr<Vec3b>(i, 0);
        for (int j = 0; j < cols; ++j) {
            switch (data[j]) {
                case 1:
                    dest_data[j] = kBlue;
                    break;
                case 2:
                    dest_data[j] = kGreen;
                    break;
                case 3:
                    dest_data[j] = kRed;
                    break;
                default:
                    break;
            }
        }
    }
    timer.End();
    std::cout << "c pointer spend time: " << timer.AverageTime() << " us" << '\n';
    imshow(kTitle, dest);
    waitKey(0);

    // c指针方法耗时在100~160us波动，LUT方法耗时在400~500us附近，即使去掉merge的耗时，也要超过200us。

    return 0;
}
